package volatileStudy;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 思考：
 * 单例真的能够实现实例的唯一么？
 * 不能，反射和序列化会打破实例唯一的情况
 *
 * 在不同执行环境下的单例实现
 */
public class SingletonTest {
    public static void main(String[] args) throws FileNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
//        SingletonOperationClass.doucleCheckLazySingleton();
//        DapoSingletonOnly.serializeable();
        SortTest.testsort();
    }
}

class SingletonOperationClass{
    /**
     * 饿汉式单例验证
     */
    public static void eagerSingleton(){
        //饿汉式
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                EagerSingleton singletonInstance = EagerSingleton.getSingletonInstance();
                System.out.println(Thread.currentThread().getName()+"创建的单例对象的hash码："+singletonInstance);
            }, String.valueOf(i)).start();
        }
    }

    /**
     * 懒汉式单例验证
     */
    public static void lazySingleton(){
        //饿汉式
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                LazySingleton singletonInstance = LazySingleton.getSingletonInstance();
                System.out.println(Thread.currentThread().getName()+"创建的单例对象的hash码："+singletonInstance);
            }, String.valueOf(i)).start();
        }
    }

    /**
     * 串行创建对象
     */
    public static void syncLazySingleton(){
        //饿汉式
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                LazySingleton singletonInstance = LazySingleton.bySyncGetSingletonInstance();
                System.out.println(Thread.currentThread().getName()+"创建的单例对象的hash码："+singletonInstance);
            }, String.valueOf(i)).start();
        }
    }

    /**
     * 双端检索
     */
    public static void doucleCheckLazySingleton(){
        //饿汉式
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                LazySingleton singletonInstance = LazySingleton.bySyncGetSingletonInstance();
                System.out.println(Thread.currentThread().getName()+"创建的单例对象的hash码："+singletonInstance);
            }, String.valueOf(i)).start();
        }
    }
}

/**
 * 单线程情况下：
 *  分为饿汉式和懒汉式
 */
class EagerSingleton{
    private static EagerSingleton singleton = new EagerSingleton();
    private EagerSingleton(){}
    public static EagerSingleton getSingletonInstance(){
        return singleton;
    }
}

/**
 * 懒汉式单例
 */
class LazySingleton implements Serializable{
    private static LazySingleton singleton;
    private static volatile LazySingleton singleton1;
    private LazySingleton(){}

    /**
     * 并行创建对象的时候有可能出现创建多个实例的情况
     * @return
     */
    public static LazySingleton getSingletonInstance(){
        if (singleton == null){
            singleton = new LazySingleton();
        }
        return singleton;
    }

    /**
     * 解决并行情况下创建对象出现创建了多个实例的问题
     *
     * 加了synchronize的方法同一时刻只有一个线程能够执行，别的线程都会阻塞直到执行任务的线程结束之后才能执行任务；
     * 由于指令重排的存在，可能造成创建的对象存在多个实例的情况
     * @return
     */
    public static synchronized LazySingleton bySyncGetSingletonInstance(){
        if (singleton == null){
            singleton = new LazySingleton();
        }
        return singleton;
    }

    /**
     * 双端检索   --解决指令重排情况下串行单例方法出现多例的情况
     * @return
     */
    public static LazySingleton doubleCheckGetSingletonInstance(){
        if (singleton1 == null){
            synchronized (LazySingleton.class){
                if (singleton1 == null){
                    singleton1 = new LazySingleton();
                }
            }
        }
        return singleton1;
    }

    /**
     * 解决序列化下出现的多实例情况
     * @return
     */
    private Object readResolve() {
        return singleton1;
    }
}

//=====================思考：单例真的能够实现实例唯一么？
//序列化打破单例的实例唯一
class DapoSingletonOnly{
    /**
     * 序列化方式
     */
    static void serializeable() throws FileNotFoundException {
        Class<String> stringClass = String.class;
        Constructor<?>[] constructors = stringClass.getConstructors();
        //先将单例对象放到文件当中
        try(ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("Singleton.txt"));

        ){
            //将对象写入文件
            outputStream.writeObject(LazySingleton.doubleCheckGetSingletonInstance());
            //从文件中 读取对象
            File file = new File("Singleton.txt");
            ObjectInputStream ois =  new ObjectInputStream(new FileInputStream(file));
            LazySingleton newInstance = (LazySingleton) ois.readObject();
            System.out.println(newInstance == LazySingleton.doubleCheckGetSingletonInstance());
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

class SortTest{
    public static void sortMethod(){
        int x = 11;
        int y = 12;
        x = x + 5;
        y = x*x;
        System.out.println("y = " + y);
        System.out.println("x = " + x);
    }

    public static void testsort(){
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                sortMethod();
            },String.valueOf(i)).start();
        }
    }

}